package com.AI.AIDemo.Demos.Web.CentralNervousSystem;

import com.AI.AIDemo.Demos.Web.Config.AIConfig;
import com.AI.AIDemo.Demos.Web.Entity.ConvolutionalAndLinearLayerNeuralNetworksEntity;
import com.AI.AIDemo.Demos.Web.Entity.MultilayerFeedforwardNeuralEntity;
import com.AI.AIDemo.Demos.Web.Entity.SonInputNeuronEntity;
import com.AI.AIDemo.Demos.Web.Service.ServiceImpl.OutBackImpl;

import lombok.extern.slf4j.Slf4j;
import org.dromara.easyai.nerveCenter.ModelParameter;
import org.dromara.easyai.nerveEntity.Nerve;
import org.dromara.easyai.nerveEntity.SensoryNerve;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author 大力王
 * {@code @Date} 2025/4/27-27-13:49
 * 脑中枢神经主体类
 * 开始了
 * sensoryNerve.postMessage(FatherInputNeuronEntity.eventId, fatherInputNeuronEntity.getParameter(), fatherInputNeuronEntity.isStudy(), fatherInputNeuronEntity.getE(), fatherInputNeuronEntity.getOutBack());
 */
@Component
@Slf4j
public class CentralNervous {

    /**
     * 神经网络管理器是构建神经网络的总控开关，它负责配置参数与创建网络结构的主类。
     */
    @Resource
    private AIConfig aiConfig;

    /**
     * 感知神经单元
     */
    @Resource
    private Nerve nerve ;

    /**
     * 输出回调类，是在输出状态下，接收神经网络的最终输出结果的回调。它只有在神经网络处于输出状态时，才会有输出回调
     */
    private OutBackImpl outBackImpl ;

    /**
     * 测试神经网络
     *
     * @throws Exception 抛出异常
     */
    public ModelParameter modelParameterTest() throws Exception {
        MultilayerFeedforwardNeuralEntity multilayerFeedforwardNeuralEntity = new MultilayerFeedforwardNeuralEntity();
        multilayerFeedforwardNeuralEntity.setInitPower(true);
        multilayerFeedforwardNeuralEntity.setShowLog(true);
        multilayerFeedforwardNeuralEntity.setSoftMax(false);
        multilayerFeedforwardNeuralEntity.setCustomEncoding(null);

        ConvolutionalAndLinearLayerNeuralNetworksEntity convolutionalAndLinearLayerNeuralNetworksEntity = getConvolutionalAndLinearLayerNeuralNetworksEntity();
//        完成初始化---初始化一个多层前馈神经网络
        aiConfig.getNerveManager().init( multilayerFeedforwardNeuralEntity.isInitPower(), multilayerFeedforwardNeuralEntity.isShowLog(), multilayerFeedforwardNeuralEntity.isSoftMax(), multilayerFeedforwardNeuralEntity.getCustomEncoding());
//        完成初始化---初始化一个卷积+线性层神经网络
        aiConfig.getNerveManager().initImageNet(convolutionalAndLinearLayerNeuralNetworksEntity.getChannelNo(),
                convolutionalAndLinearLayerNeuralNetworksEntity.getKernLen(),
                convolutionalAndLinearLayerNeuralNetworksEntity.getXSize(),
                convolutionalAndLinearLayerNeuralNetworksEntity.getYSize(),
                convolutionalAndLinearLayerNeuralNetworksEntity.isSoftMax(),
                convolutionalAndLinearLayerNeuralNetworksEntity.isShowLog(),
                convolutionalAndLinearLayerNeuralNetworksEntity.getConvStudyPoint(),
                convolutionalAndLinearLayerNeuralNetworksEntity.getConvActiveFunction(),
                convolutionalAndLinearLayerNeuralNetworksEntity.getMinFeatureValue(),
                convolutionalAndLinearLayerNeuralNetworksEntity.getOneConvRate(),
                convolutionalAndLinearLayerNeuralNetworksEntity.isNorm());

//        输入神经元是负责向网络输入特征参数的入口类，它负责向内部输入参数，最终得到结果
        return aiConfig.getNerveManager().getConvModel();
    }

    private static ConvolutionalAndLinearLayerNeuralNetworksEntity getConvolutionalAndLinearLayerNeuralNetworksEntity() {
        ConvolutionalAndLinearLayerNeuralNetworksEntity convolutionalAndLinearLayerNeuralNetworksEntity = new ConvolutionalAndLinearLayerNeuralNetworksEntity();
        convolutionalAndLinearLayerNeuralNetworksEntity.setChannelNo(1);
        convolutionalAndLinearLayerNeuralNetworksEntity.setKernLen(3);
        convolutionalAndLinearLayerNeuralNetworksEntity.setXSize(28);
        convolutionalAndLinearLayerNeuralNetworksEntity.setYSize(28);
        convolutionalAndLinearLayerNeuralNetworksEntity.setSoftMax(false);
        convolutionalAndLinearLayerNeuralNetworksEntity.setShowLog(true);
        convolutionalAndLinearLayerNeuralNetworksEntity.setConvStudyPoint(0.0025F);
        convolutionalAndLinearLayerNeuralNetworksEntity.setOneConvRate(0.01f);
        convolutionalAndLinearLayerNeuralNetworksEntity.setMinFeatureValue(5);
        convolutionalAndLinearLayerNeuralNetworksEntity.setNorm(true);
        return convolutionalAndLinearLayerNeuralNetworksEntity;
    }

    private SonInputNeuronEntity getInputNeuronEntity() throws Exception {
        Integer eventId = aiConfig.getSensoryNerve().getId();

        Map<Integer, Float> E = new HashMap<>(30);
        E.put(eventId, 12.3F);

        SonInputNeuronEntity sonInputNeuronEntity = new SonInputNeuronEntity();
        sonInputNeuronEntity.setParameter(0.0025F);
        sonInputNeuronEntity.setStudy(true);
        sonInputNeuronEntity.setE(E);
        sonInputNeuronEntity.setOutBack(null);
        sonInputNeuronEntity.setNeedMatrix(false);

        return sonInputNeuronEntity;
    }

    /**
     * 测试输入神经网络
     * @return List<SensoryNerve>
     * @throws Exception 报错
     */
    public List<SensoryNerve> TestSensoryNerveList() throws Exception {
        //        注入模型
        aiConfig.getNerveManager().insertConvModel(this.modelParameterTest());

        nerve = aiConfig.getSensoryNerve();
        SonInputNeuronEntity sonInputNeuronEntity = getInputNeuronEntity();
        Nerve nerve2 = new SensoryNerve(3,2,4);
        Nerve nerve3 = new SensoryNerve(4,3,2);
        List<Nerve> nerveList = new ArrayList<>();
        Map<Integer, Float> E = new HashMap<>(30);
        E.put(nerve.getId(), sonInputNeuronEntity.getParameter());
        E.put(nerve2.getId(), sonInputNeuronEntity.getParameter());
        E.put(nerve3.getId(), sonInputNeuronEntity.getParameter());

        nerveList.add(nerve);
        nerveList.add(nerve2);
        nerveList.add(nerve3);

        nerve.setDendrites( E );
        nerve.connectSonOnly(nerve2);
        nerve.connectSonOnly(nerve3);
        nerve3.connectFatherOnly(nerve);
        nerve2.connectFatherOnly(nerve);
        nerve3.setDendrites( E );
        nerve2.setDendrites( E );

        nerve.connect(nerveList);

        log.info("神经网络结构11："+nerve.getDendrites()+"+++子神经："+nerveList.get(1).getId()+"+++父神经："+nerveList.get(0).getId());

//        获取卷积神经网络的输入神经元，卷积神经网络输入参数，只需要向该神经元输入参数即可注意：向卷积神经网络输入特征矩阵时，必须通过该方法获取的输入神经元进行输入
        aiConfig.getSensoryNerve().postMessage(SonInputNeuronEntity.eventId, sonInputNeuronEntity.getParameter(), sonInputNeuronEntity.isStudy(), sonInputNeuronEntity.getE(), sonInputNeuronEntity.getOutBack());
        log.info("神经网络结构12："+sonInputNeuronEntity.getOutBack());

        return aiConfig.getNerveManager().getSensoryNerves();
    }
}
